from flask import request, jsonify, g
from flask_jwt_extended import jwt_required
import datetime
from bson import ObjectId

from app.api.v1 import api_bp
from app import mongo
from app.utils.auth import permission_required
from app.schemas.billing import BillingSchema, BillingUpdateSchema, BillingQuerySchema
from app.utils.common import normalize_data, paginate, generate_id

@api_bp.route('/billing/patients/<id>/summary', methods=['GET'])
@jwt_required()
@permission_required('billing:read')
def get_patient_billing_summary(id):
    """获取患者费用汇总"""
    # 查找患者
    patient = None
    if ObjectId.is_valid(id):
        patient = mongo.db.patients.find_one({'_id': ObjectId(id)})
    
    if not patient:
        patient = mongo.db.patients.find_one({'patientId': id})
    
    if not patient:
        return jsonify({
            'success': False,
            'message': '患者不存在'
        }), 404
    
    # 获取查询参数
    visit_id = request.args.get('visitId')
    start_date = request.args.get('startDate')
    end_date = request.args.get('endDate')
    
    # 构建查询条件
    query = {'patientId': str(patient['_id'])}
    
    if visit_id:
        query['visitId'] = visit_id
    
    # 处理日期范围
    if start_date:
        try:
            start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d')
            query['createdAt'] = {'$gte': start_date}
        except ValueError:
            return jsonify({
                'success': False,
                'message': '开始日期格式错误，应为YYYY-MM-DD'
            }), 400
    
    if end_date:
        try:
            end_date = datetime.datetime.strptime(end_date, '%Y-%m-%d')
            end_date = end_date.replace(hour=23, minute=59, second=59)
            if 'createdAt' in query:
                query['createdAt']['$lte'] = end_date
            else:
                query['createdAt'] = {'$lte': end_date}
        except ValueError:
            return jsonify({
                'success': False,
                'message': '结束日期格式错误，应为YYYY-MM-DD'
            }), 400
    
    # 查询账单
    billings = list(mongo.db.billings.find(query))
    
    # 处理查询结果
    total_amount = 0
    paid_amount = 0
    unpaid_amount = 0
    insurance_amount = 0
    
    billing_items_by_type = {
        'registration': {'count': 0, 'amount': 0},
        'prescription': {'count': 0, 'amount': 0},
        'medical_record': {'count': 0, 'amount': 0},
        'service': {'count': 0, 'amount': 0},
        'other': {'count': 0, 'amount': 0}
    }
    
    billing_summary = []
    
    for billing in billings:
        # 计算总金额
        total_amount += billing.get('totalAmount', 0)
        
        # 根据状态计算已付和未付金额
        if billing.get('status') == '已支付':
            paid_amount += billing.get('totalAmount', 0)
        else:
            unpaid_amount += billing.get('totalAmount', 0)
        
        # 计算医保支付金额
        insurance_info = billing.get('insuranceInfo', {})
        if insurance_info and insurance_info.get('isInsurance'):
            insurance_amount += insurance_info.get('insurancePay', 0)
        
        # 统计各类型项目
        for item in billing.get('items', []):
            item_type = item.get('type', 'other')
            if item_type in billing_items_by_type:
                billing_items_by_type[item_type]['count'] += 1
                billing_items_by_type[item_type]['amount'] += item.get('amount', 0)
        
        # 添加到账单摘要
        normalized_billing = normalize_data(billing)
        billing_summary.append({
            'id': normalized_billing['id'],
            'billingId': normalized_billing.get('billingId', ''),
            'visitId': normalized_billing.get('visitId', ''),
            'totalAmount': normalized_billing.get('totalAmount', 0),
            'status': normalized_billing.get('status', ''),
            'itemCount': len(normalized_billing.get('items', [])),
            'createdAt': normalized_billing.get('createdAt', '')
        })
    
    # 统计分类汇总
    summary_by_type = []
    for item_type, data in billing_items_by_type.items():
        if data['count'] > 0:
            summary_by_type.append({
                'type': item_type,
                'count': data['count'],
                'amount': data['amount']
            })
    
    # 获取患者基本信息
    patient_info = {
        'id': str(patient['_id']),
        'patientId': patient.get('patientId', ''),
        'name': patient.get('name', ''),
        'gender': patient.get('gender', ''),
        'age': patient.get('age', '')
    }
    
    # 构建响应
    return jsonify({
        'success': True,
        'data': {
            'patientInfo': patient_info,
            'summary': {
                'totalAmount': total_amount,
                'paidAmount': paid_amount,
                'unpaidAmount': unpaid_amount,
                'insuranceAmount': insurance_amount,
                'billingCount': len(billings)
            },
            'summaryByType': summary_by_type,
            'billings': billing_summary
        }
    }), 200

@api_bp.route('/billings', methods=['GET'])
@jwt_required()
@permission_required('billing:read')
def get_billings():
    """获取账单列表"""
    # 获取查询参数
    page = request.args.get('page', 1, type=int)
    limit = request.args.get('limit', 20, type=int)
    sort_by = request.args.get('sortBy', 'createdAt')
    order = request.args.get('order', 'desc')
    
    # 构建查询条件
    query = {}
    
    # 按患者ID筛选
    patient_id = request.args.get('patientId')
    if patient_id:
        query['patientId'] = patient_id
    
    # 按就诊ID筛选
    visit_id = request.args.get('visitId')
    if visit_id:
        query['visitId'] = visit_id
    
    # 按状态筛选
    status = request.args.get('status')
    if status and status != 'all':
        query['status'] = status
    
    # 按日期范围筛选
    start_date = request.args.get('startDate')
    if start_date:
        try:
            start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d')
            query['createdAt'] = {'$gte': start_date}
        except ValueError:
            pass
    
    end_date = request.args.get('endDate')
    if end_date:
        try:
            end_date = datetime.datetime.strptime(end_date, '%Y-%m-%d')
            end_date = end_date.replace(hour=23, minute=59, second=59)
            if 'createdAt' in query:
                query['createdAt']['$lte'] = end_date
            else:
                query['createdAt'] = {'$lte': end_date}
        except ValueError:
            pass
    
    # 确定排序
    sort_direction = -1 if order.lower() == 'desc' else 1
    
    # 获取数据
    billings_cursor = mongo.db.billings.find(query).sort(sort_by, sort_direction)
    
    # 分页
    paginated_data = paginate(billings_cursor, page, limit)
    
    # 标准化数据
    billings = []
    for billing in paginated_data['items']:
        # 获取患者信息
        patient_name = ''
        if 'patientId' in billing:
            patient_id = billing['patientId']
            if isinstance(patient_id, str) and ObjectId.is_valid(patient_id):
                patient_id = ObjectId(patient_id)
            patient = mongo.db.patients.find_one({'_id': patient_id})
            if patient:
                patient_name = patient.get('name', '')
        
        # 标准化账单数据
        normalized_billing = normalize_data(billing)
        normalized_billing['patientName'] = patient_name
        billings.append(normalized_billing)
    
    return jsonify({
        'success': True,
        'data': {
            'total': paginated_data['total'],
            'page': paginated_data['page'],
            'limit': paginated_data['per_page'],
            'billings': billings
        }
    }), 200

@api_bp.route('/billings/<id>', methods=['GET'])
@jwt_required()
@permission_required('billing:read')
def get_billing(id):
    """获取账单详情"""
    # 查询账单
    billing = None
    if ObjectId.is_valid(id):
        billing = mongo.db.billings.find_one({'_id': ObjectId(id)})
    
    if not billing:
        billing = mongo.db.billings.find_one({'billingId': id})
    
    if not billing:
        return jsonify({
            'success': False,
            'message': '账单不存在'
        }), 404
    
    # 获取患者信息
    patient_info = None
    if 'patientId' in billing:
        patient_id = billing['patientId']
        if isinstance(patient_id, str) and ObjectId.is_valid(patient_id):
            patient_id = ObjectId(patient_id)
        patient = mongo.db.patients.find_one({'_id': patient_id})
        if patient:
            patient_info = {
                'id': str(patient['_id']),
                'patientId': patient.get('patientId', ''),
                'name': patient.get('name', ''),
                'gender': patient.get('gender', ''),
                'age': patient.get('age', '')
            }
    
    # 获取关联的支付记录
    payments = []
    if ObjectId.is_valid(id):
        payments_cursor = mongo.db.payments.find({'billingId': str(billing['_id'])})
        for payment in payments_cursor:
            payments.append({
                'id': str(payment['_id']),
                'paymentId': payment.get('paymentId', ''),
                'amount': payment.get('amount', 0),
                'paymentMethod': payment.get('paymentMethod', ''),
                'status': payment.get('status', ''),
                'paidAt': payment.get('paidAt', ''),
                'createdAt': payment.get('createdAt', '')
            })
    
    # 标准化数据
    normalized_billing = normalize_data(billing)
    
    return jsonify({
        'success': True,
        'data': {
            'billing': normalized_billing,
            'patientInfo': patient_info,
            'payments': payments
        }
    }), 200

@api_bp.route('/billings', methods=['POST'])
@jwt_required()
@permission_required('billing:create')
def create_billing():
    """创建账单"""
    # 验证请求数据
    schema = BillingSchema()
    errors = schema.validate(request.json)
    if errors:
        return jsonify({
            'success': False,
            'message': '请求数据验证失败',
            'errors': errors
        }), 400
    
    data = request.json
    
    # 验证患者是否存在
    patient_id = data.get('patientId')
    if not mongo.db.patients.find_one({'_id': ObjectId(patient_id)}):
        return jsonify({
            'success': False,
            'message': '患者不存在'
        }), 400
    
    # 生成账单ID
    data['billingId'] = generate_id('B')
    
    # 计算医保金额
    if 'insuranceInfo' in data and data['insuranceInfo'].get('isInsurance'):
        insurance_info = data['insuranceInfo']
        ratio = insurance_info.get('reimbursementRatio', 0)
        total = data.get('totalAmount', 0)
        
        if ratio > 0 and total > 0:
            insurance_pay = total * ratio
            patient_pay = total - insurance_pay
            
            insurance_info['insurancePay'] = round(insurance_pay, 2)
            insurance_info['patientPay'] = round(patient_pay, 2)
    
    # 设置创建时间和更新时间
    now = datetime.datetime.utcnow()
    data['createdAt'] = now
    data['updatedAt'] = now
    
    # 保存到数据库
    result = mongo.db.billings.insert_one(data)
    
    return jsonify({
        'success': True,
        'message': '账单创建成功',
        'data': {
            'id': str(result.inserted_id),
            'billingId': data['billingId'],
            'totalAmount': data['totalAmount'],
            'status': data['status'],
            'createdAt': now.isoformat()
        }
    }), 201

@api_bp.route('/billings/<id>', methods=['PUT'])
@jwt_required()
@permission_required('billing:update')
def update_billing(id):
    """更新账单"""
    # 查询账单
    billing = None
    if ObjectId.is_valid(id):
        billing = mongo.db.billings.find_one({'_id': ObjectId(id)})
    
    if not billing:
        return jsonify({
            'success': False,
            'message': '账单不存在'
        }), 404
    
    # 验证请求数据
    schema = BillingUpdateSchema()
    errors = schema.validate(request.json)
    if errors:
        return jsonify({
            'success': False,
            'message': '请求数据验证失败',
            'errors': errors
        }), 400
    
    data = request.json
    
    # 计算医保金额
    if 'insuranceInfo' in data and data['insuranceInfo'].get('isInsurance'):
        insurance_info = data['insuranceInfo']
        ratio = insurance_info.get('reimbursementRatio', 0)
        
        # 如果更新了总金额，需要重新计算医保和自费部分
        if 'totalAmount' in data:
            total = data['totalAmount']
        else:
            total = billing.get('totalAmount', 0)
        
        if ratio > 0 and total > 0:
            insurance_pay = total * ratio
            patient_pay = total - insurance_pay
            
            insurance_info['insurancePay'] = round(insurance_pay, 2)
            insurance_info['patientPay'] = round(patient_pay, 2)
    
    # 更新时间
    data['updatedAt'] = datetime.datetime.utcnow()
    
    # 更新数据库
    mongo.db.billings.update_one({'_id': ObjectId(id)}, {'$set': data})
    
    return jsonify({
        'success': True,
        'message': '账单更新成功',
        'data': None
    }), 200

@api_bp.route('/billings/<id>', methods=['DELETE'])
@jwt_required()
@permission_required('billing:delete')
def delete_billing(id):
    """删除账单"""
    # 查询账单
    billing = None
    if ObjectId.is_valid(id):
        billing = mongo.db.billings.find_one({'_id': ObjectId(id)})
    
    if not billing:
        return jsonify({
            'success': False,
            'message': '账单不存在'
        }), 404
    
    # 检查是否有关联的支付记录
    payment_count = mongo.db.payments.count_documents({'billingId': str(billing['_id'])})
    if payment_count > 0:
        return jsonify({
            'success': False,
            'message': f'无法删除账单，当前有{payment_count}个支付记录关联到此账单'
        }), 400
    
    # 删除数据库中的账单
    mongo.db.billings.delete_one({'_id': ObjectId(id)})
    
    return jsonify({
        'success': True,
        'message': '账单删除成功',
        'data': None
    }), 200 